#include <iostream>
using namespace std;
#include <string>
#include <unistd.h>
#include <cstdlib>
#include <vector>
#include <ctime>
#include <wait.h>
#include "task.hpp"
// 匿名管道
enum
{
    UsageError = 1, // 输入错误
    ArgError = 2,   // 参数错误
    pipeError = 3   // 管道错误
};

// 父进程用这个类描述子进程---"先描述，再组织"
class Channel
{
public:
    // 构造
    Channel(int wfd, pid_t sub_id, const string &name)
        : _wfd(wfd), _sub_process_id(sub_id), _name(name)
    {
    }
    // 析构
    ~Channel()
    {
        _wfd = 0;
        _sub_process_id = 0;
        _name = "";
    }
    // 查看
    void DebugPrint()
    {
        cout << "wfd:" << _wfd << ",_sub_process_id:" << _sub_process_id << ",_name:" << _name << endl;
    }
    string name()
    {
        return _name;
    }
    int wfd()
    {
        return _wfd;
    }
    pid_t pid()
    {
        return _sub_process_id;
    }
    void Close()
    {
        close(_wfd);
        cout << "pid:" << _sub_process_id << "已被关掉" << endl;
    }

private:
    int _wfd;              // 父进程要对其进行写入时所依赖的文件描述符
    pid_t _sub_process_id; // 子进程的id
    string _name;          // 子进程的名称
};

void Usage(const string &proc)
{
    cout << "Usage: " << proc << " subprocess-num" << endl;
}

class processpool
{
public:
    processpool(int sub_process_num)
        : _sub_process_num(sub_process_num)
    {
    }
    ~processpool()
    {
        for (int number = 0; number < _sub_process_num; number++)
        {
            channels.pop_back();
        }
        _sub_process_num = 0;
    }
    // 创建子进程
    int CreatProcess(work_t work)
    {
        vector<int> fds;
        // 创建子进程+管道
        for (int number = 0; number < _sub_process_num; number++)
        {
            int pipefd[2] = {0};  // 管道读写的fd
            int n = pipe(pipefd); // 创建管道
            // n==-1 管道创建失败
            if (n < 0)
            {
                return pipeError;
            }
            sleep(1);
            pid_t id = fork(); // 创建子进程
            if (id == 0)
            {
                if (!fds.empty())
                {
                    cout << "close wfd :";
                    for (auto fd : fds)
                    {
                        close(fd);
                        cout << fd << " ";
                    }
                    cout << endl;
                }
                // child process
                // 子进程作为读取端
                close(pipefd[1]); // 子进程关闭写入端
                // 执行任务
                // 将文件描述符表中下标为0的内容修改为pipefd[0]，读取依旧为0
                dup2(pipefd[0], 0); // 重定向操作
                work(pipefd[0]);
                // 执行完成之后退出
                exit(0);
            }
            else
            {
                // father process
                // 父进程作为写入端
                close(pipefd[0]); // 父进程关闭读取端
                string name = "Channel-" + to_string(number);
                channels.push_back(Channel(pipefd[1], id, name));
                fds.push_back(pipefd[1]);
            }
        }
        return 0;
    }
    // 选择下一个子进程，返回其下标
    int NextChannel()
    {
        static int next = 0; // 均衡的选择
        int c = next;
        next++;
        next %= channels.size();
        return c;
    }
    // 打印信息
    void Debug()
    {
        for (auto &c : channels)
        {
            c.DebugPrint();
        }
    }
    // 发送任务
    void SendTaskCode(int channel, uint32_t code)
    {
        cout << "send code" << code << "to " << channels[channel].name() << " sub process id:" << channels[channel].pid() << endl;
        write(channels[channel].wfd(), &code, sizeof(code));
    }
    // 关闭
    void KillAll()
    {
        for (int number = 0; number < _sub_process_num; number++)
        {
            channels[number].Close();
            cout << channels[number].name() << "读端已被关闭,pid为:" << channels[number].pid() << endl;
            pid_t pid = channels[number].pid();
            int rid = waitpid(pid, nullptr, 0); // 阻塞式等待
            if (rid == pid)
            {
                cout << "pid:" << pid << ",等待成功!!!" << endl;
            }
        }
    }
    // 等待回收
    // void Wait()
    // {
    //     for (auto &a : channels)
    //     {
    //         pid_t pid = a.pid();
    //         int rid = waitpid(pid, nullptr, 0); // 阻塞式等待
    //         if (rid == pid)
    //         {
    //             cout << "pid:" << pid << ",等待成功!!!" << endl;
    //         }
    //     }
    // }

private:
    vector<Channel> channels; // 创建管理子进程的vector
    int _sub_process_num;     // 记录需要创建的子进程的个数
};
// 控制子进程
void CtrlProcessPool(processpool *processpool_ptr, int cnt)
{
    while (cnt)
    {
        // 1.选择一个进程编号
        int channel = processpool_ptr->NextChannel();
        sleep(1);
        // cout << "name:" << channel.name() << endl;
        //  2.选择一个任务
        uint32_t code = NextTask();
        // 发送任务
        processpool_ptr->SendTaskCode(channel, code);
        cnt--;
    }
}

// 格式: ./processpool 创建进程个数
int main(int argc, char *argv[2])
{
    // 输入错误提示
    if (argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num = stoi(argv[1]); // 创建子进程个数
    // 创建的子进程个数<=0，就退出
    if (sub_process_num <= 0)
    {
        return ArgError;
    }
    srand((uint64_t)time(nullptr));
    // 创建子进程+管道
    processpool *processpool_ptr = new processpool(sub_process_num);
    processpool_ptr->CreatProcess(worker);
    processpool_ptr->Debug();
    // 控制子进程
    CtrlProcessPool(processpool_ptr, 10);
    cout << "任务执行结束" << endl;
    // sleep(100);
    //  等待回收子进程
    //  1.让所有子进程全部退出
    processpool_ptr->KillAll();
    // 2.所有资源都被回收
    // processpool_ptr->Wait();
    cout << "父进程pid:" << getpid() << ",父进程退出" << endl;
    delete (processpool_ptr);
    return 0;
}